from rest_framework import serializers
from . import models
from course.models import Course
from rest_framework.exceptions import ValidationError
import uuid
from luffyapi.libs.al_pay import alipay, gateway
from django.conf import settings


class OrderSerializer(serializers.ModelSerializer):
    """订单序列化类"""
    # 规定前端传什么样的数据过来，fields里写什么，如：{course:[1,2,3], total_amount:100, subject:xx商品, pay_type:1}
    # 对于course，需要将course:[1,2,3]处理成course:[obj1,obj2,obj3]，可以用 PrimaryKeyRelatedField()
    # queryset参数表示course字段的id和Course表做关联
    course = serializers.PrimaryKeyRelatedField(queryset=Course.objects.all(), write_only=True, many=True)
    # user字段也需要，但不是从前端传来，是从jwt来

    class Meta:
        model = models.Order
        fields = ['total_amount', 'subject', 'pay_type', 'course']

    def _check_price(self, attrs):
        total_amount = attrs.get('total_amount')  # 获取订单总价
        course_list = attrs.get('course')  # 拿出课程对象组成的列表
        total_price = 0
        for course in course_list:  # 循环课程对象列表，从每一个课程对象中拿出价格进行累加
            total_price += course.price
        if total_price != total_amount:
            raise ValidationError('价格不合法')
        return total_amount  # 将总价返回，方便生成支付链接时使用

    def _get_out_trade_no(self):
        return str(uuid.uuid4()).replace('-', '')  # 将生成的订单号中的-去掉

    def _get_user(self):
        # 需要request对象（需要视图重写create方法，通过context把request对象传入）
        request = self.context.get('request')
        return request.user

    def _get_pay_url(self, out_trade_no, total_amount, subject):
        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no=out_trade_no,  # 订单号
            total_amount=float(total_amount),  # 商品金额 total_amount是Decimal类型，支付宝识别不了，必须转成float类型
            subject=subject,  # 商品名称
            # 下面地址要用公网地址才能收到支付宝的回调
            return_url=settings.RETURN_URL,  # get同步回调 前台地址 写支付成功
            notify_url=settings.NOTIFY_URL  # post异步回调 后台地址 改订单状态
        )
        return gateway + order_string

    def _before_create(self, attrs, user, out_trade_no, pay_url=None):
        attrs['user'] = user  # 把用户放入数据中
        attrs['out_trade_no'] = out_trade_no  # 把订单号放入数据中
        self.context['pay_url'] = pay_url  # 把订单链接放入context以便于返回给前端

    def validate(self, attrs):
        """存进表之前对数据做校验"""
        # 1、订单总价校验
        total_amount = self._check_price(attrs)
        # 2、生成订单号
        out_trade_no = self._get_out_trade_no()
        # 3、支付用户：request.user
        user = self._get_user()
        # 对订单总价做判断，如果总价为零，就无须生成支付链接，直接走入库
        if total_amount == 0:
            self._before_create(attrs, user, out_trade_no)
            return attrs
        # 4、支付链接生成
        pay_url = self._get_pay_url(out_trade_no, total_amount, attrs.get('subject'))
        # 5、入库（两个表）的信息准备
        self._before_create(attrs, user, out_trade_no, pay_url)
        return attrs

    def create(self, validated_data):
        """
        重写create方法
        给Order和OrderDetail中新增数据
        """
        course_list = validated_data.pop('course')
        order = models.Order.objects.create(**validated_data)
        for course in course_list:
            models.OrderDetail.objects.create(order=order, course=course, price=course.price, real_price=course.price)

        return order
